#include "types.h"
#include "defs.h"
#include "param.h"
#include "mmu.h"
#include "x86.h"
#include "proc.h"
#include "spinlock.h"

#include "stat.h"
#include "fs.h"
#include "file.h"
#include "fcntl.h"

struct {
	struct spinlock lock;
	int procCount;
	int numOfSwapped;
	struct proc proc[NPROC];
} ptable;

static struct proc *initproc;

int nextpid = 1;
int swapperAction; // 0 invalid, -1 swapout, >0 pid of proc to swapin

extern void forkret(void);
extern void trapret(void);

static void wakeup1(void *chan);
int canSwap();
struct file * createSwapFile(int pid, int * fd);
struct proc* getProcessWithMinPages();
struct proc* getProcessWithMaxPages();

int
strcmp(const char *p, const char *q)
{
	while(*p && *p == *q)
		p++, q++;
	return (uchar)*p - (uchar)*q;
}


void
pinit(void)
{
	initlock(&ptable.lock, "ptable");
	ptable.procCount = 0;
	ptable.numOfSwapped=0;
}

// Print a process listing to console.  For debugging.
// Runs when user types ^P on console.
// No lock to avoid wedging a stuck machine further.
void
procdump(void)
{
	static char *states[] = {
			[UNUSED]    "unused",
			[EMBRYO]    "embryo",
			[SLEEPING]  "sleep ",
			[RUNNABLE]  "runble",
			[RUNNING]   "run   ",
			[ZOMBIE]    "zombie"
	};
	int i;
	struct proc *p;
	char *state;
	uint pc[10];
	char s1[3] = "/S";
	char s2[1] = "";
	char * s3;
	int numOfPages=0;

	for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
		if(p->state == UNUSED)
			continue;
		if(p->state >= 0 && p->state < NELEM(states) && states[p->state])
			state = states[p->state];
		else
			state = "???";

		numOfPages = p->sz/PGSIZE;
		s3 = p->swappedout ? s1:s2;



		cprintf("%d %s pgs:%d swpCnt:%d%s %s", p->pid, state,numOfPages,p->swapCounter,s3, p->name);
		if(p->state == SLEEPING){
			getcallerpcs((uint*)p->context->ebp+2, pc);
			for(i=0; i<10 && pc[i] != 0; i++)
				cprintf(" %p", pc[i]);
		}
		cprintf("\n");
	}
	cprintf("%d\% free pages in the system\n",freePagesRatio());
}


// Return the address of the PTE in page table pgdir
// that corresponds to linear address va.  If create!=0,
// create any required page table pages.
static pte_t *
walkpgdir(pde_t *pgdir, const void *va, int create)
{
	uint r;
	pde_t *pde;
	pte_t *pgtab;

	/*1*/pde = &pgdir[PDX(va)];
	if(*pde & PTE_P){
		/*2*/ pgtab = (pte_t*) PTE_ADDR(*pde);
	} else if(!create || !(r = (uint) kalloc()))
		return 0;
	else {
		pgtab = (pte_t*) r;
		// Make sure all those PTE_P bits are zero.
		memset(pgtab, 0, PGSIZE);
		// The permissions here are overly generous, but they can
		// be further restricted by the permissions in the page table
		// entries, if necessary.
		*pde = PADDR(r) | PTE_P | PTE_W | PTE_U;
	}
	/*3*/return &pgtab[PTX(va)];
}


// Look in the process table for an UNUSED proc.
// If found, change state to EMBRYO and return it.
// Otherwise return 0.
static struct proc*
allocproc(void)
{
	struct proc *p;
	char *sp;

	acquire(&ptable.lock);
	for(p = ptable.proc; p < &ptable.proc[NPROC]; p++)
		if(p->state == UNUSED)
			goto found;
	release(&ptable.lock);
	return 0;

	found:
	p->state = EMBRYO;
	p->pid = nextpid++;
	p->swappedout =0;
	p->swapCounter = 0;
	ptable.procCount++;
	release(&ptable.lock);

	// Allocate kernel stack if possible.
	if((p->kstack = kalloc()) == 0){
		p->state = UNUSED;
		return 0;
	}
	sp = p->kstack + KSTACKSIZE;

	// Leave room for trap frame.
	sp -= sizeof *p->tf;
	p->tf = (struct trapframe*)sp;

	// Set up new context to start executing at forkret,
	// which returns to trapret (see below).
	sp -= 4;
	*(uint*)sp = (uint)trapret;

	sp -= sizeof *p->context;
	p->context = (struct context*)sp;
	memset(p->context, 0, sizeof *p->context);
	p->context->eip = (uint)forkret;

	return p;
}

// Set up first user process.
void
userinit(void)
{
	struct proc *p;
	extern char _binary_initcode_start[], _binary_initcode_size[];

	p = allocproc();
	initproc = p;
	if(!(p->pgdir = setupkvm()))
		panic("userinit: out of memory?");
	inituvm(p->pgdir, _binary_initcode_start, (int)_binary_initcode_size);
	p->sz = PGSIZE;
	memset(p->tf, 0, sizeof(*p->tf));
	p->tf->cs = (SEG_UCODE << 3) | DPL_USER;
	p->tf->ds = (SEG_UDATA << 3) | DPL_USER;
	p->tf->es = p->tf->ds;
	p->tf->ss = p->tf->ds;
	p->tf->eflags = FL_IF;
	p->tf->esp = PGSIZE;
	p->tf->eip = 0;  // beginning of initcode.S

	safestrcpy(p->name, "initcode", sizeof(p->name));
	p->cwd = namei("/");

	p->state = RUNNABLE;
}


void createInternalProcess(const char *name, void (*entrypoint)())
{
	struct proc *p;
	extern char _binary_initcode_start[], _binary_initcode_size[];

	p = allocproc();
	initproc = p;
	if(!(p->pgdir = setupkvm()))
		panic("userinit: out of memory?");
	inituvm(p->pgdir, _binary_initcode_start, (int)_binary_initcode_size);
	p->sz = PGSIZE;
	memset(p->tf, 0, sizeof(*p->tf));
	p->tf->cs = (SEG_UCODE << 3) | DPL_USER;
	p->tf->ds = (SEG_UDATA << 3) | DPL_USER;
	p->tf->es = p->tf->ds;
	p->tf->ss = p->tf->ds;
	p->tf->eflags = FL_IF;
	p->tf->esp = PGSIZE;
	p->tf->eip = 0;  // beginning of initcode.S
	///// this function is EXACTLY the same as userinit, except for addition of the next line: ***/
	p->context->eip = (uint)entrypoint;

	safestrcpy(p->name, name, sizeof(p->name));
	p->cwd = namei("/");

	p->state = RUNNABLE;
}

// Grow current process's memory by n bytes.
// Return 0 on success, -1 on failure.
int
growproc(int n)
{
	uint sz = proc->sz;
	if(n > 0){
		if(!(sz = allocuvm(proc->pgdir, sz, sz + n)))
			return -1;
	} else if(n < 0){
		if(!(sz = deallocuvm(proc->pgdir, sz, sz + n)))
			return -1;
	}
	proc->sz = sz;
	switchuvm(proc);
	return 0;
}

// Create a new process copying p as the parent.
// Sets up stack to return as if from system call.
// Caller must set state of returned proc to RUNNABLE.
int
fork(void)
{
	int i, pid;
	struct proc *np;

	// Allocate process.
	if((np = allocproc()) == 0)
		return -1;

	// Copy process state from p.
	if(!(np->pgdir = copyuvm(proc->pgdir, proc->sz))){
		kfree(np->kstack);
		np->kstack = 0;
		np->state = UNUSED;
		return -1;
	}
	np->sz = proc->sz;
	np->parent = proc;
	*np->tf = *proc->tf;

	// Clear %eax so that fork returns 0 in the child.
	np->tf->eax = 0;

	for(i = 0; i < NOFILE; i++)
		if(proc->ofile[i])
			np->ofile[i] = filedup(proc->ofile[i]);
	np->cwd = idup(proc->cwd);

	pid = np->pid;
	np->state = RUNNABLE;
	safestrcpy(np->name, proc->name, sizeof(proc->name));
	return pid;
}

// Exit the current process.  Does not return.
// An exited process remains in the zombie state
// until its parent calls wait() to find out it exited.
void
exit(void)
{
	struct proc *p;
	int fd;

	if(proc == initproc)
		panic("init exiting");

	// Close all open files.
	for(fd = 0; fd < NOFILE; fd++){
		if(proc->ofile[fd]){
			fileclose(proc->ofile[fd]);
			proc->ofile[fd] = 0;
		}
	}

	iput(proc->cwd);
	proc->cwd = 0;

	acquire(&ptable.lock);

	// Parent might be sleeping in wait().
	wakeup1(proc->parent);

	// Pass abandoned children to init.
	for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
		if(p->parent == proc){
			p->parent = initproc;
			if(p->state == ZOMBIE)
				wakeup1(initproc);
		}
	}

	// Jump into the scheduler, never to return.
	proc->state = ZOMBIE;
	ptable.procCount--;
	sched();
	panic("zombie exit");
}

// Wait for a child process to exit and return its pid.
// Return -1 if this process has no children.
int
wait(void)
{
	struct proc *p;
	int havekids, pid;

	acquire(&ptable.lock);
	for(;;){
		// Scan through table looking for zombie children.
		havekids = 0;
		for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
			if(p->parent != proc)
				continue;
			havekids = 1;
			if(p->state == ZOMBIE){
				// Found one.
				pid = p->pid;
				kfree(p->kstack);
				p->kstack = 0;
				freevm(p->pgdir);
				p->state = UNUSED;
				p->pid = 0;
				p->parent = 0;
				p->name[0] = 0;
				p->killed = 0;
				release(&ptable.lock);
				return pid;
			}
		}

		// No point waiting if we don't have any children.
		if(!havekids || proc->killed){
			release(&ptable.lock);
			return -1;
		}

		// Wait for children to exit.  (See wakeup1 call in proc_exit.)
		sleep(proc, &ptable.lock);  //DOC: wait-sleep
	}
}

void swtchToProc(struct proc * p){

	// Switch to chosen process.  It is the process's job
	// to release ptable.lock and then reacquire it
	// before jumping back to us.
	proc = p;
	switchuvm(p);
	p->state = RUNNING;
	swtch(&cpu->scheduler, proc->context);
	switchkvm();

}

void swtchToKProc(struct proc * p){

	// Switch to chosen process.  It is the process's job
	// to release ptable.lock and then reacquire it
	// before jumping back to us.
	proc = p;
	//switchuvm(p);
	p->state = RUNNING;
	swtch(&cpu->scheduler, proc->context);
	//switchkvm();

}


// Per-CPU process scheduler.
// Each CPU calls scheduler() after setting itself up.
// Scheduler never returns.  It loops, doing:
//  - choose a process to run
//  - swtch to start running that process
//  - eventually that process transfers control
//      via swtch back to the scheduler.
void
scheduler(void)
{
	struct proc *p;
	struct proc * swapper =0;

	// Find our swapper
	acquire(&ptable.lock);
	for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
		if(strcmp(p->name,SWAPPERNAME)==0){
			swapper = p;
			break;
		}
	}
	release(&ptable.lock);
	if (!swapper)
		panic("scheduler: no swapper found");

	for(;;){

		// Enable interrupts on this processor.
		sti();

		// Loop over process table looking for process to run.
		acquire(&ptable.lock);
		for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
			if(p->state != RUNNABLE)
				continue;


			while ((freePagesRatio() < MEM_T) && canSwap()){
				swapperAction = -1;
				swtchToKProc(swapper);
				//cprintf("ratio:%d\n",freePagesRatio());
			}

			if (p != swapper){

				while (p->swappedout){
					// swap in p
					swapperAction = (uint)p;
					swtchToKProc(swapper);
					//cprintf("1\n");

				}
				//cprintf("test\n");
				swtchToProc(p);
			}



			// Process is done running for now.
			// It should have changed its p->state before coming back.
			proc = 0;
		}
		release(&ptable.lock);

	}
}

// Enter scheduler.  Must hold only ptable.lock
// and have changed proc->state.
void
sched(void)
{
	int intena;

	if(!holding(&ptable.lock))
		panic("sched ptable.lock");
	if(cpu->ncli != 1)
		panic("sched locks");
	if(proc->state == RUNNING)
		panic("sched running");
	if(readeflags()&FL_IF)
		panic("sched interruptible");
	intena = cpu->intena;
	swtch(&proc->context, cpu->scheduler);
	cpu->intena = intena;
}

// Give up the CPU for one scheduling round.
void
yield(void)
{
	acquire(&ptable.lock);  //DOC: yieldlock
	proc->state = RUNNABLE;
	sched();
	release(&ptable.lock);
}

// A fork child's very first scheduling by scheduler()
// will swtch here.  "Return" to user space.
void
forkret(void)
{
	// Still holding ptable.lock from scheduler.
	release(&ptable.lock);

	// Return to "caller", actually trapret (see allocproc).
}

// Atomically release lock and sleep on chan.
// Reacquires lock when awakened.
void
sleep(void *chan, struct spinlock *lk)
{
	if(proc == 0)
		panic("sleep");

	if(lk == 0)
		panic("sleep without lk");

	// Must acquire ptable.lock in order to
	// change p->state and then call sched.
	// Once we hold ptable.lock, we can be
	// guaranteed that we won't miss any wakeup
	// (wakeup runs with ptable.lock locked),
	// so it's okay to release lk.
	if(lk != &ptable.lock){  //DOC: sleeplock0
		acquire(&ptable.lock);  //DOC: sleeplock1
		release(lk);
	}

	// Go to sleep.
	proc->chan = chan;
	proc->state = SLEEPING;
	sched();

	// Tidy up.
	proc->chan = 0;

	// Reacquire original lock.
	if(lk != &ptable.lock){  //DOC: sleeplock2
		release(&ptable.lock);
		acquire(lk);
	}
}

// Wake up all processes sleeping on chan.
// The ptable lock must be held.
static void
wakeup1(void *chan)
{
	struct proc *p;

	for(p = ptable.proc; p < &ptable.proc[NPROC]; p++)
		if(p->state == SLEEPING && p->chan == chan)
			p->state = RUNNABLE;
}

// Wake up all processes sleeping on chan.
void
wakeup(void *chan)
{
	acquire(&ptable.lock);
	wakeup1(chan);
	release(&ptable.lock);
}

// Kill the process with the given pid.
// Process won't exit until it returns
// to user space (see trap in trap.c).
int
kill(int pid)
{
	struct proc *p;

	acquire(&ptable.lock);
	for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
		if(p->pid == pid){
			p->killed = 1;
			// Wake process from sleep if necessary.
			if(p->state == SLEEPING)
				p->state = RUNNABLE;
			release(&ptable.lock);
			return 0;
		}
	}
	release(&ptable.lock);
	return -1;
}


// Is the directory dp empty except for "." and ".." ?
static int
isdirempty(struct inode *dp)
{
  int off;
  struct dirent de;

  for(off=2*sizeof(de); off<dp->size; off+=sizeof(de)){
    if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
      panic("isdirempty: readi");
    if(de.inum != 0)
      return 0;
  }
  return 1;
}

static struct inode*
fcreate(char *path, short type, short major, short minor)
{
	uint off;
	struct inode *ip, *dp;
	char name[DIRSIZ];

	if((dp = nameiparent(path, name)) == 0)
		return 0;
	ilock(dp);

	if((ip = dirlookup(dp, name, &off)) != 0){
		iunlockput(dp);
		ilock(ip);
		if(type == T_FILE && ip->type == T_FILE)
			return ip;
		iunlockput(ip);
		return 0;
	}

	if((ip = ialloc(dp->dev, type)) == 0)
		panic("create: ialloc");

	ilock(ip);
	ip->major = major;
	ip->minor = minor;
	ip->nlink = 1;
	iupdate(ip);

	if(type == T_DIR){  // Create . and .. entries.
		dp->nlink++;  // for ".."
		iupdate(dp);
		// No ip->nlink++ for ".": avoid cyclic ref count.
		if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0)
			panic("create dots");
	}

	if(dirlink(dp, name, ip->inum) < 0)
		panic("create: dirlink");

	iunlockput(dp);
	return ip;
}

static int
my_fdalloc(struct file *f)
{
	int fd;

	for(fd = 0; fd < NOFILE; fd++){
		if(proc->ofile[fd] == 0){
			proc->ofile[fd] = f;
			return fd;
		}
	}
	return -1;
}


int
my_open(char * path, int omode, int * fd)
{

	struct file *f;
	struct inode *ip;


	if(omode & O_CREATE){
		if((ip = fcreate(path, T_FILE, 0, 0)) == 0)
			return -1;
	} else {
		if((ip = namei(path)) == 0)
			return -1;
		ilock(ip);
		if(ip->type == T_DIR && omode != O_RDONLY){
			iunlockput(ip);
			return -1;
		}
	}

	if((f = filealloc()) == 0 || (*fd = my_fdalloc(f)) < 0){
		if(f)
			fileclose(f);
		iunlockput(ip);
		return -1;
	}
	iunlock(ip);

	f->type = FD_INODE;
	f->ip = ip;
	f->off = 0;
	f->readable = !(omode & O_WRONLY);
	f->writable = (omode & O_WRONLY) || (omode & O_RDWR);
	return (uint)f;
}


int
my_close(int fd, struct file *f)
{

	proc->ofile[fd] = 0;
	fileclose(f);
	return 0;
}

int
my_read(struct file *f, char *p, int n)
{
	return fileread(f, p, n);
}

int
my_write(struct file *f, char *p, int n)
{
	return filewrite(f, p, n);
}

int
my_unlink(char *path)
{
  struct inode *ip, *dp;
  struct dirent de;
  char name[DIRSIZ];
  uint off;


  if((dp = nameiparent(path, name)) == 0)
    return -1;
  ilock(dp);

  // Cannot unlink "." or "..".
  if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0){
    iunlockput(dp);
    return -1;
  }

  if((ip = dirlookup(dp, name, &off)) == 0){
    iunlockput(dp);
    return -1;
  }
  ilock(ip);

  if(ip->nlink < 1)
    panic("unlink: nlink < 1");
  if(ip->type == T_DIR && !isdirempty(ip)){
    iunlockput(ip);
    iunlockput(dp);
    return -1;
  }

  memset(&de, 0, sizeof(de));
  if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
    panic("unlink: writei");
  if(ip->type == T_DIR){
    dp->nlink--;
    iupdate(dp);
  }
  iunlockput(dp);

  ip->nlink--;
  iupdate(ip);
  iunlockput(ip);
  return 0;
}


// Create PTEs for linear addresses starting at la that refer to
// physical addresses starting at pa. la and size might not
// be page-aligned.
static int
my_mappages(pde_t *pgdir, void *la, uint size, uint pa, int perm)
{
	char *a = PGROUNDDOWN(la);
	char *last = PGROUNDDOWN(la + size - 1);

	while(1){
		pte_t *pte = walkpgdir(pgdir, a, 1);
		if(pte == 0)
			return 0;
		if(*pte & PTE_P)
			panic("remap");
		*pte = pa | perm | PTE_P;
		if(a == last)
			break;
		a += PGSIZE;
		pa += PGSIZE;
	}
	return 1;
}

void swapIn(struct proc * p){

	// for each page in file
	char path[8] = "00.swap";
	struct file *f;
	char * page;
	int fd;
	char * tmpva;

	//cprintf("start IN: %d\n",p->pid);
	if (!p->swappedout)
		panic("swapin: trying to swap in a process that is already in memory.");

	if (p->pid < 100){
		path[0] = (p->pid / 10) + '0';
		path[1] = (p->pid % 10) + '0';
	}

	if ((	f = (struct file *)my_open(path,O_RDONLY,&fd)) <= 0)
		panic("swapin: my_open failed");

	// init the p->pgdir. pgdir = setupkvm
	if(!(p->pgdir = setupkvm()))
		panic("swapin: cant init pgdir for swapped in process");
	while(1){
		// kalloc - get the new physical address.
		if ((page = kalloc())==0)
			panic("swapin: can't kalloc memory for page");
		// va = read va from file
		if (my_read(f,(char*)&tmpva,sizeof(char*)) <=0 )
			break;

		// page = read page from file.
		if (my_read(f,page,PGSIZE) <0 )
			panic("swapin: cant read page from swap file");

		// COPY the page from file to *kalloc_result
		if (!my_mappages(p->pgdir, tmpva, PGSIZE,(uint)page,PTE_W|PTE_U))
			panic("swapin: my_mappages FAILED");

	}

	// The last one is unused
	kfree(page);

	if (my_close(fd,f) < 0 )
		panic("swapin: close file failed");

	// rm the file
	my_unlink(path);

	p->swappedout = 0;
	ptable.numOfSwapped--;
	//cprintf("end SWAPIN: %d\n",p->pid);
}


void swapOut(struct proc * p){
	int fd;
	int i;
	struct file *f;
	int numOfuserPages = 160;
	char * tmpva;
	char* pAddress;


	//cprintf("start OUT: %d\n",p->pid);

	acquire(&ptable.lock);
	p->swappedout = 1;
	p->swapCounter++;
	ptable.numOfSwapped++;
	release(&ptable.lock);


	f = createSwapFile(p->pid,&fd);

	if (!f)
		panic("swapout: couldn't create swap file");

	for(i = 0; i < numOfuserPages; i++){

		tmpva = (char*)(i*PGSIZE);

		if (!(pAddress = uva2ka(p->pgdir,tmpva )))
			continue;

		if (my_write(f,(char*)(&tmpva),4) < 0)
			panic("swapout: file write fail");
		if (my_write(f,pAddress,PGSIZE) < 0)
			panic("swapout: file write fail");
	}

	if (my_close(fd,f) < 0 )
		panic("swapout: close file failed");
	// free the whole memory of the proc. maybe inefficient, will do so far

	//cprintf("b4 free: %d\n",getNumOfFreePages());
	freevm(p->pgdir);
	//cprintf("after free: %d\n",getNumOfFreePages());
	//cprintf("end OUT: %d\n",p->pid);

}




int canSwap(){
	// the number of processes - the number of processes swapped out
	return ((ptable.procCount-ptable.numOfSwapped) > 4);

}

void swapperRun(){

	struct proc * toswap;
	release(&ptable.lock);

	while(1){
		toswap = 0;
		switch (swapperAction){
		case 0: // aaakwaaaaard
			cprintf("aaakwaaaaard\n");
			break;
		case -1: //swap out
			toswap = 0;
#ifdef SELECTION
#if SELECTION==MIN
			toswap = getProcessWithMinPages();
#endif
#if SELECTION==MAX

			toswap = getProcessWithMaxPages();
#endif
#endif
			if (toswap){
				//cprintf("WILL SWAPOUT pid %d\n",toswap->pid);
				swapOut(toswap);
			}
			break;
		default:
			// case>0 => pid to swap in
			//cprintf("about to swapIN\n");
			toswap = (struct proc*)swapperAction;
			swapIn(toswap);
			break;
		}

		swapperAction = 0;
		//cprintf("SWAPPER: yield\n");
		yield();
	}
}


int isSwapOutImutable(struct proc * p){

	if (strcmp(p->name,SWAPPERNAME)==0)
		return 1;

	if (strcmp(p->name,"sh")==0)
		return 1;

	if (strcmp(p->name,"init")==0)
		return 1;
	if (p->swappedout)
		return 1;
	return 0;
}

struct proc* getProcessWithMinPages(){
	struct proc * p;
	int min = PHYSTOP;
	struct proc* minProcess = 0;
	for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
		if(p->sz < min && p->state==RUNNABLE && !isSwapOutImutable(p)){
			min = p->sz;
			minProcess = p;
		}
	}
	return minProcess;
}

struct proc* getProcessWithMaxPages(){
	struct proc * p;
	int max = 0;
	struct proc* maxProcess = 0;
	for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
		if(p->sz > max && p->state==RUNNABLE && !isSwapOutImutable(p)){
			//cprintf("GREAT SUCCESS!!\n");
			max = p->sz;
			maxProcess = p;
		}
	}
	return maxProcess;
}

struct file * createSwapFile(int pid, int * fd){
	struct file *f;

	char path[8] = "00.swap";

	if (pid < 100){
		path[0] = (pid / 10) + '0';
		path[1] = (pid % 10) + '0';
	}

	f = (struct file *)my_open(path, O_WRONLY | O_CREATE, fd);

	return f;
}



int freePagesRatio(){
	int numOfFreePages=0;
	int numOfPages = PHYSTOP/PGSIZE;
	numOfFreePages =  getNumOfFreePagesShort();
	return (numOfFreePages*100/numOfPages);
}
